package com.example.shop.controller;

import com.example.shop.domain.Order;
import com.example.shop.domain.Product;
import com.example.shop.enums.ResultExceptionEnum;
import com.example.shop.exception.ShopException;
import com.example.shop.form.OrderForm;
import com.example.shop.service.OrderService;
import com.example.shop.service.ProductService;
import com.example.shop.utils.ResultVOUtil;
import com.example.shop.vo.ResultVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.security.Principal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@RequestMapping("/order")
@RestController
@CrossOrigin(origins = {}, methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.OPTIONS})
@Slf4j
public class OrderController {

    @Autowired
    private OrderService orderService;

    @Autowired
    private ProductService productService;


    /**
     * 根据指定的订单状态将订单导出到excel表中,若订单是新订单 -->则修改状态为已导出
     * @param response 导出订单响应返回
     * @param orderStatus 指定的订单状态
     * @param orderType 订单类别
     */
    @RequestMapping("/exportorder")
    public void exportOrder(HttpServletResponse response,
                            @RequestParam("orderstatus") Integer orderStatus,
                            @RequestParam("ordertype") Integer orderType) {
        orderService.exportByOrderStatusAndOrderType(response, orderStatus,orderType);
    }

    /**
     * 根据提交的orderForm来创建一个订单,将订单的状态表示为:未支付状态
     *
     * @param orderForm     指定的orderForm
     * @param bindingResult 数据绑定器，验证订单数据
     * @return 创建的订单
     */
    @PostMapping("/create")
    public ResultVO<Order> create(@Valid OrderForm orderForm, BindingResult bindingResult, Principal principal) {
        if (bindingResult.hasErrors()) {
            throw new ShopException(ResultExceptionEnum.PARAM_ERROR, bindingResult.getFieldError().getDefaultMessage());
        }
        Order order = orderService.create(orderForm, principal.getName());
        return ResultVOUtil.success(order);
    }


    /**
     * 根据指定的订单id进行支付操作，若支付成功，则会修改订单状态: 未支付状态 -> 新订单状态
     *
     * @param orderId 订单的ID
     * @return 若支付成功，返回支付成功的订单
     */
    @PostMapping("/pay")
    public ResultVO<Order> pay(@RequestParam("orderid") String orderId) {
        return ResultVOUtil.success(orderService.paid(orderId));
    }

    /**
     * 完结订单处理,根据已导出订单的id,修改订单状态: 已导出订单 -> 完结订单
     *
     * @param orderId 指定的订单id
     * @return 若修改成功返回修改的订单
     */
    @PostMapping("/finish")
    public ResultVO<Order> finishOrder(@RequestParam("orderid") String orderId) {
        return ResultVOUtil.success(orderService.finish(orderId));
    }


    /**
     * 获取所有订单  默认分页page:0  size:10
     *
     * @param page 页数，默认第0页
     * @param size 每页的数据项，默认10个
     * @param orderType 订单类别
     * @return 返回对应页数的数据项的集合
     */
    @GetMapping("/getlist")
    public ResultVO<Page<Order>> getListByOrderType(@RequestParam(value = "page", defaultValue = "0") Integer page,
                                                    @RequestParam(value = "size", defaultValue = "10") Integer size,
                                                    @RequestParam("ordertype") Integer orderType) {
        Sort sort = new Sort(Sort.Direction.DESC, "createtime");
        PageRequest pageRequest = new PageRequest(page, size, sort);
        Page<Order> orderPage = orderService.findByOrderType(pageRequest, orderType);
        return ResultVOUtil.success(orderPage);
    }

    /**
     * 通过订单号查询订单，并返回查询的订单
     *
     * @param orderId 指定的订单号
     * @return 查询到的订单
     */
    @PostMapping("/findbyorderid")
    public ResultVO findByOrderId(@RequestParam("orderid") String orderId) {
        Order order = orderService.findOne(orderId);
        Set<String> productIdSet = order.getItems().stream().map(orderItem -> orderItem.getProduct().getId()).collect
                (Collectors.toSet());
//        List<Product> productList = this.productService.findByIdIn(productIdSet);//TODO 似乎有一二级缓存出现，神奇！
        Map<String, Object> result = new HashMap<>();
        result.put("order", order);
//        result.put("products", productList);
        //TODO 需要把这个封装一下
        return ResultVOUtil.success(result);
    }

    /**
     * 通过Openid查询订单,按照分页模式显示
     *
     * @param principal 唯一标识符
     * @param page      第几页，第0页开始
     * @param size      一页展示的数据项，默认10项
     * @return 返回该页所展示的所有数据项的集合
     */
    @PostMapping("/getlistbyopenid")
    public ResultVO<Page<Order>> getListByOpenId(Principal principal,
                                                 @RequestParam(value = "page", defaultValue = "0") Integer page,
                                                 @RequestParam(value = "size", defaultValue = "10") Integer size) {

        String openid = principal.getName();

        if (StringUtils.isEmpty(openid)) {
            throw new ShopException(ResultExceptionEnum.PARAM_ERROR);
        }

        PageRequest pageRequest = new PageRequest(page-1, size);

        Page<Order> result = orderService.findByOpenid(openid, pageRequest);

        return ResultVOUtil.success(result);
    }

    /**
     * 根据指定的订单id进行删除订单操作，若删除成功，返回成功状态表示
     *
     * @param id 指定的订单id
     * @return 返回成功的状态表示
     */
    @PostMapping("/delete")
    public ResultVO delete(@RequestParam("orderid") String id) {
        orderService.delete(id);
        return ResultVOUtil.success();
    }

    /**
     * 通过订单状态查询订单，返回的订单按照分页模式，默认一页10个数据项
     *
     * @param orderStatus 订单的状态
     * @param page        页数
     * @param size        单位页上的数据项
     * @param orderType 订单类别
     * @return 订单集合
     */
    @PostMapping("/getlistbyorderstatus")
    public ResultVO<Page<Order>> getListByPayStatus(@RequestParam("orderstatus") Integer orderStatus,
                                                    @RequestParam(value = "page", defaultValue = "0") Integer page,
                                                    @RequestParam(value = "size", defaultValue = "10") Integer size,
                                                    @RequestParam("ordertype") Integer orderType) {
        if (StringUtils.isEmpty(orderStatus)) {
            throw new ShopException(ResultExceptionEnum.PARAM_ERROR);
        }
        PageRequest pageRequest = new PageRequest(page-1, size);
        Page<Order> order = orderService.findByOrderTypeAndOrderStatus(orderType, orderStatus, pageRequest);
        return ResultVOUtil.success(order);
    }

    /**
     * 取消订单
     *
     * @param orderId 根据id取消订单
     * @return 返回成功的取消信息
     */
    @PostMapping("/cancel")
    public ResultVO<Order> cancelOrder(@RequestParam("orderid") String orderId) {
        return ResultVOUtil.success(orderService.cancel(orderId));
    }

    /**
     * 根据商品类型查询订单,返回对应商品类别的所有商品的集合
     *
     * @param productType 商品的类别
     * @return 对应商品类别的所有商品的集合
     */
    @PostMapping("findbyproducttype")
    public ResultVO<List<Order>> findByProductType(@RequestParam("producttype") Integer productType) {
        return ResultVOUtil.success(orderService.findByProductType(productType));
    }

    /**
     * 根据number查找订单
     * @param orderNumber 指定的订单number
     * @return 指定number对应的订单
     */
    @PostMapping("/findbyordernumber")
    public ResultVO<Order> findByOrderNumber(@RequestParam("ordernumber") String orderNumber){
        return ResultVOUtil.success(orderService.findByOrderNumber(orderNumber));
    }

    /**
     * 根据给定的时间段进行统计所有的订单，具体格式:
     *   总订单:
     *   新订单:
     *   已导出订单:
     *   完结订单:
     *   作废订单:
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 返回该时间段的所有订单
     */
    @PostMapping("/statisticbetweendate")
    public ResultVO<Map> statisticBetweenDate(@RequestParam("starttime") Long startTime,
                                              @RequestParam("endtime") Long endTime) {
        Map<Integer, Long> map = orderService.statisticsOrder(startTime, endTime);
        return ResultVOUtil.success(map);
    }

}
